#pragma once
#include <d3dx9.h>
#include <string>
#include <list>
#include "matrix.h"
#include "boundingbox.h"
#include "physics.h"

/**
 * Klasa wezla sceny.
 *
 * @author Krzysztof Klein
 * @version 0.1
 */
class SceneNode
{

public:

	/**
	 * Flagi wezla.
	 * Flagi sa ustawiane w konstruktorze na podstawie nazwy wezla,
	 * np "kill_lava" -> Kill, "skybox" -> Normal
	 */
	enum Flag
	{
		// Normalny wezel
		Normal,

		// Punkt poczatkowy kulki
		SpawnPoint,

		// Siatka koncowa
		Finish,

		// Bez sprawdzania kolizji
		NoClip,

		// Siatka 'zabijajaca' kulke
		Kill,

		// Sky box
		SkyBox,

		// Gracza
		Player
	};

	/**
	 * Zraca flage wezla na podstawie jego nazwy
	 */
	static Flag getFlagFromName(const std::string &name);

protected:

	/**
	 * Nazwa wezla
	 */
	std::string name;

	/**
	 * Macierz lokalnej transformacji
	 */
	Matrix localTransformation;

	/**
	 * Macierz bezwzglednej transformacji
	 */
	Matrix absoluteTransformation;

	/**
	 * Wezel rodzica
	 */
	SceneNode* parentNode;

	/**
	 * Podwezly
	 */
	std::list<SceneNode*> subNodes;

	/**
	 * Prostopadloscian otaczajacy
	 */
	BoundingBox boundingBox;

	/**
	 * Flaga wezla
	 */
	Flag flag;

public:

	/**
	 * Konstruktor
	 */
	SceneNode(SceneNode* parentNode, std::string &name = std::string("unnamed"));

	/**
	 * Destruktor
	 */
	virtual ~SceneNode();


	/**
	 * Renderuje wezel sceny
	 */
	virtual void draw();


	/**
	 * Odswierza macierz bezwzglednej transformacji
	 */
	virtual void refreshAbsoluteTransformation(bool recursive = false);


	/**
	 * Laduje wezel sceny i jego podwezly z danych pliku X.
	 */
	virtual bool loadFromXof(LPD3DXFILEDATA xofFileData);


	/**
	 * Nazwa wezla
	 */
	const std::string& getName() const { return name; }
	std::string& getName() { return name; }
	void setName(std::string &newName) { name = newName; }


	/**
	 * Macierz lokalnej transformacji
	 */
	const Matrix& getLocalTransformation() const { return localTransformation; }
	Matrix& getLocalTransformation() { return localTransformation; }
	void setLocalTransformation(const Matrix &mtx) { localTransformation = mtx; }


	/**
	 * Dodaje lokalna transformacje
	 */
	void addTransformation(const Matrix &mtx) { localTransformation *= mtx; }


	/**
	 * Macierz bezwzglednej transformacji
	 */
	const Matrix& getAbsoluteTransformation() const { return absoluteTransformation; }


	/**
	 * Wezel rodzica
	 */
	const SceneNode* getParentNode() const { return parentNode; }
	SceneNode* getParentNode() { return parentNode; }

	/**
	 * Podwezly
	 */
	const std::list<SceneNode*>& getSubNodes() const { return subNodes; }
	void addSubNode(SceneNode* node) { if(node) { subNodes.push_back(node); } }
	std::list<SceneNode*>& getSubNodes() { return subNodes; }

	/**
	 * Znajduje podwezel na podstawie flagi
	 */
	SceneNode* getSubNodeFromFlag(Flag f) const;

	/**
	 * Prostopadloscian otaczajacy
	 */
	const BoundingBox& getBoundingBox() const { return boundingBox; }

	/**
	 * Flaga wezla
	 */
	Flag getFlag() const { return flag; }

	/**
	 * Sprawdza kolizje
	 */
	virtual void checkCollision(const BoundingBox &playerBox, 
		float playerRadius, Physics::CollisionPacket &col) const;

};
